Skip to main content

Immutable Classes in Java

Banner java icon

πŸš€ The Fun Guide to Java Immutability πŸŽ‰β€‹

πŸ”₯ What is Immutability?​

Imagine having a magical box πŸ§™β€β™‚οΈ that, once sealed, never lets you change what’s inside. That’s what an immutable object is in Javaβ€”once created, it stays the same forever! ❄️ Any modifications? Nope! You’ll have to create a brand-new object instead.

Let’s see an example with the legendary String class:

String string = "test";
String newString = string.toLowerCase(); // Creates a new String

Here, string remains untouched, while newString holds the modified value. Java is all about playing it safe! 😎


πŸ—‚οΈ Immutability in Collections​

Java gives us three cool ways to create immutable collections:

1️⃣ Unmodifiable collections
2️⃣ Immutable factory methods (Java 9+)
3️⃣ Immutable copies (Java 10+)

Collections.unmodifiableList(recordList);  // Unmodifiable list
List.of(new Record(1, "test")); // Factory methods in Java 9
List.copyOf(recordList); // Java 10

🚨 Warning: These are only "shallowly immutable." You can’t add or remove elements, but the existing elements inside can still mutate. 😱

Example:

List<Record> list = List.of(new Record(1, "value"));
System.out.println(list); // [Record(id=1, name=value)]

list.get(0).setName("modified-value");
System.out.println(list); // [Record(id=1, name=modified-value)]

To achieve true immutability, only add immutable objects to the collection. This ensures that even if someone gets a reference to an element, they CAN’T modify it. πŸš€


🎨 How to Create an Immutable Class​

Java suggests the following to craft a bulletproof immutable class:

βœ… No setter methods! Setters allow change, which we don’t want. ❌ βœ… Make fields final and private. Once set, never modified. πŸ” βœ… Prevent method overriding. Just make the class final. 🎭 βœ… Handle mutable fields cautiously! If an object has a list, return a new copy instead of the original.

final class Record {
private final long id;
private final String name;
private final List<String> tokens;

public Record(long id, String name, List<String> tokens) {
this.id = id;
this.name = name;
this.tokens = List.copyOf(tokens);
}

public long getId() { return id; }
public String getName() { return name; }
public List<String> getTokens() { return tokens; }

@Override
public String toString() {
return "Record{" +
"id=" + id +
", name='" + name + '\'' +
", tokens=" + tokens +
'}';
}
}

Let’s try modifying it:

List<String> tokens = new ArrayList<>();
tokens.add("active");

Record record = new Record(1, "value", tokens);
System.out.println(record); // Record{id=1, name='value', tokens=[active]}

record.getTokens().add("new token");
System.out.println(record); // Record{id=1, name='value', tokens=[active]}

BOOM! πŸ”₯ The original object remains unchanged!


⚑ Immutability with Java Records​

Java records (introduced in Java 14) remove boilerplate code while making objects immutable. πŸŽ‰

record Record(long id, String name, List<String> tokens){
public List<String> tokens() {
return List.copyOf(tokens);
}
}

Testing immutability:

List<String> tokens = new ArrayList<>();
tokens.add("active");

Record record = new Record(1, "value", tokens);
System.out.println(record); // Record{id=1, name='value', tokens=[active]}

record.tokens().add("new token");
System.out.println(record); // Record{id=1, name='value', tokens=[active]}

Records enforce immutability with less code! πŸ†


πŸ“š Immutable Classes in JDK​

Java already has a ton of built-in immutable classes:

βœ” java.lang.String
βœ” Wrapper classes (Integer, Long, Double, etc.)
βœ” java.math.BigInteger and BigDecimal
βœ” Unmodifiable collections (Collections.singletonMap())
βœ” java.util.UUID
βœ” Java Enums πŸ”₯
βœ” Java 8 Date/Time API (LocalDate, LocalTime)
βœ” Record types 🎯


🎯 Why Should You Care?​

βœ… Predictability​

Immutable objects never change, making debugging much easier! 🧐

βœ… Thread-Safety​

Since nothing changes, no race conditions or synchronization nightmares. Win! πŸ†

βœ… No More Copying!​

Immutable objects don’t need a copy constructor or clone(). Java just reuses them. πŸ”„

βœ… Better Performance πŸš€β€‹

Caching? Check! Memoization? Check! Immutable objects are perfect for optimization.


🎬 Conclusion​

Immutable classes in Java:

βœ… Are simple to construct, test, and use
βœ… Eliminate synchronization issues
βœ… Make great Map keys and Set elements
βœ… Ensure β€˜failure atomicity’ (If an error occurs, objects are never left in a bad state)

Pro Tip: Always aim to make your Java classes immutable. It saves you from a ton of headaches down the road! πŸ˜ƒβ€‹

πŸš€ Happy Coding! πŸš€